home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr47 / comasm.zip / COMASM.ASM
Assembly Source File  |  1992-01-12  |  47KB  |  1,604 lines

  1.         PAGE    63,132                  ;(63 lines long, 132 columns wide)
  2.         TITLE   Mark Stout      COMASM       5/10/89
  3. .SALL
  4. ;==============================================================================
  5. ;
  6. ;       Mark Stout      COMASM.EXE     5/10/89
  7. ;
  8. ;       COMASM is an integrated terminal emulation package combining two modes,
  9. ;       VT52 and CHAT.  While in the VT52 emulation mode, COMASM will impersonate
  10. ;       a DEC VT52, transmitting, receiving and interpreting all escape
  11. ;       sequences in this terminal's command set.  While in the CHAT mode, COMASM
  12. ;       allows messages to be sent between two PCs.  Any characters
  13. ;       may be sent, in messages up to 256 characters long.
  14. ;
  15. ;       Data is transmitted and received through the PC's primary serial port,
  16. ;       COM1.  COMASM relies on interupts from the UART as opposed to polling
  17. ;       its registers.
  18. ;
  19. ;==============================================================================
  20.  
  21. ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^MACROS^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  22.  
  23. ;==============================================================================
  24. ;
  25. ;       DISPLAY Macro:
  26. ;
  27. ;       Displays string of characters on standard output.  String must be
  28. ;       terminated by '$'.
  29. ;
  30. ;       Format:
  31. ;
  32. ;               DISPLAY message
  33. ;
  34. ;       where message is the offset of the string.
  35. ;
  36. ;==============================================================================
  37.  
  38. DISPLAY   MACRO    MESSAGE
  39.  
  40.         PUSH    DX
  41.         PUSH    AX
  42.  
  43.         LEA     DX, MESSAGE             ;Point to offset of string
  44.         MOV     AH, 9H                  ;Use DOS function 9H
  45.         INT     21H
  46.  
  47.         POP     AX
  48.         POP     DX
  49.  
  50. ENDM
  51.  
  52. ;==============================================================================
  53. ;
  54. ;       BIN2ASCII Macro:
  55. ;
  56. ;       Converts binary value in DX to ASCII string.
  57. ;
  58. ;       Format:
  59. ;
  60. ;               BIN2ASCII length, out_buffer
  61. ;
  62. ;       where length is the # of characters for the output string, including
  63. ;       leading spaces, and out_buffer is location of output buffer.
  64. ;
  65. ;==============================================================================
  66.  
  67. BIN2ASCII  MACRO  LENGTH, OUT_BUFFER
  68.         LOCAL   ASCIILOOP, BLANK, NEXT, PAD  ;Define local labels for multiple invocations
  69.  
  70.         PUSH    AX
  71.         PUSH    BX
  72.         PUSH    CX
  73.         PUSH    DX
  74.         PUSH    DI
  75.  
  76.         MOV     CX, LENGTH              ;Set up CX as counter of ASCII digits
  77.         MOV     AX, DX                  ;Move binary value to accumulator
  78.         MOV     BX, 10                  ;Set up BX as decimal base
  79.  
  80. ASCIILOOP:
  81.         MOV     DI, CX                  ;Use DI for index relative addressing of ASCII string
  82.         CMP     AX, 0                   ;If accumulator = 0, pad left of string with blanks
  83.         JE      BLANK
  84.         MOV     DX, 0                   ;Prepare DX as high word of dividend
  85.         DIV     BX                      ;Divide remaining value by decimal base
  86.         ADD     DX, 30H                 ;Convert remainder to ASCII for use in string
  87.         MOV     [OUT_BUFFER+DI-1], DL   ;Converted remainder is next least significant digit in string
  88.         JMP     NEXT
  89.  
  90. BLANK:  CMP     CX, LENGTH              ;Checks for binary value = 0
  91.         JNE     PAD
  92.         MOV     [OUT_BUFFER+DI-1], '0'
  93.         JMP     NEXT
  94.  
  95. PAD:    MOV     [OUT_BUFFER+DI-1], ' '  ;Pads left of string with blanks when necessary
  96. NEXT:   LOOP    ASCIILOOP               ;Calculate next digit of string
  97.  
  98.         POP     DI
  99.         POP     DX
  100.         POP     CX
  101.         POP     BX
  102.         POP     AX
  103.  
  104. ENDM
  105.  
  106. ;===============================================================================
  107. ;
  108. ;       SCROLL_UP Macro:
  109. ;
  110. ;       Uses BIOS function INT 10h, Subfunction 6, to scroll a pre-defined
  111. ;       window a given number of lines. New lines are white foreground on
  112. ;       black background.
  113. ;
  114. ;       Format:
  115. ;
  116. ;       SCROLL_UP  lines, TL_row, TL_col, BR_row, BR_col
  117. ;
  118. ;       where:  lines  = # of lines to scroll (0 for entire window)
  119. ;               TL_row = row of top, left corner
  120. ;               TL_col = column of top, left corner
  121. ;               BR_row = row of bottom, right corner
  122. ;               BR_col = column of bottom, right corner
  123. ;
  124. ;===============================================================================
  125.  
  126. SCROLL_UP       MACRO   LINES, TL_ROW, TL_COL, BR_ROW, BR_COL
  127.  
  128.         PUSH    AX
  129.         PUSH    BX
  130.         PUSH    CX
  131.         PUSH    DX
  132.  
  133.         MOV     AH, 6                   ;Choose subfunction 6
  134.         MOV     AL, LINES               ;Initialize registers
  135.         MOV     CH, TL_ROW
  136.         MOV     CL, TL_COL
  137.         MOV     DH, BR_ROW
  138.         MOV     DL, BR_COL
  139.         MOV     BH, 7
  140.  
  141.         INT     10H
  142.  
  143.         POP     DX
  144.         POP     CX
  145.         POP     BX
  146.         POP     AX
  147.  
  148. ENDM
  149.  
  150. ;===============================================================================
  151. ;
  152. ;       SCROLL_DOWN Macro:
  153. ;
  154. ;       Uses BIOS function INT 10h, Subfunction 6, to scroll a pre-defined
  155. ;       window down a given number of lines. New lines are white foreground on
  156. ;       black background.
  157. ;
  158. ;       Format:
  159. ;
  160. ;       SCROLL_DOWN  lines, TL_row, TL_col, BR_row, BR_col
  161. ;
  162. ;       where:  lines  = # of lines to scroll (0 for entire window)
  163. ;               TL_row = row of top, left corner
  164. ;               TL_col = column of top, left corner
  165. ;               BR_row = row of bottom, right corner
  166. ;               BR_col = column of bottom, right corner
  167. ;
  168. ;===============================================================================
  169.  
  170. SCROLL_DOWN     MACRO   LINES, TL_ROW, TL_COL, BR_ROW, BR_COL
  171.  
  172.         PUSH    AX
  173.         PUSH    BX
  174.         PUSH    CX
  175.         PUSH    DX
  176.  
  177.         MOV     AH, 7                   ;Choose subfunction 7
  178.         MOV     AL, LINES               ;Initialize registers
  179.         MOV     CH, TL_ROW
  180.         MOV     CL, TL_COL
  181.         MOV     DH, BR_ROW
  182.         MOV     DL, BR_COL
  183.         MOV     BH, 7
  184.  
  185.         INT     10H
  186.  
  187.         POP     DX
  188.         POP     CX
  189.         POP     BX
  190.         POP     AX
  191.  
  192. ENDM
  193.  
  194. ;===============================================================================
  195. ;
  196. ;       LOCATE Macro:
  197. ;
  198. ;       Uses BIOS function INT 10h, Subfunction 2, to position cursor.
  199. ;
  200. ;       Input:  DH = Row coordinate (0-24)
  201. ;               DL = Column coordinate (0-79)
  202. ;
  203. ;===============================================================================
  204.  
  205. LOCATE  MACRO
  206.  
  207.         PUSH    AX
  208.         PUSH    BX
  209.  
  210.         MOV     AH, 2                   ;Choose subfunction 2
  211.         MOV     BH, 0                   ;Choose video page
  212.         INT     10H
  213.  
  214.         POP     BX
  215.         POP     AX
  216.  
  217. ENDM
  218.  
  219. ;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  220.  
  221. STKSEG  SEGMENT STACK                   ;Stack segment
  222.         DB      512 DUP(?)              ;(512 bytes ought to do)
  223. STKSEG  ENDS
  224.  
  225. CSEG    SEGMENT                         ;Code segment
  226.         ASSUME  CS:CSEG, DS:CSEG, SS:STKSEG, ES:NOTHING
  227.  
  228. ;==============================================================================
  229. ;
  230. ;       MP3 Main Procedure:
  231. ;
  232. ;       Sets up data, and calls subroutines.  Also performs requested
  233. ;       mode switching and exits.
  234. ;
  235. ;==============================================================================
  236.  
  237. MAIN    PROC    FAR
  238.         MOV     AX, CSEG                ;Initialize DS register
  239.         MOV     DS, AX
  240.         JMP     OLA                     ;Jump around data
  241.  
  242. ;       Define equates, messages and buffers
  243.  
  244. MSGCAP  EQU     256
  245. CR      EQU     0DH
  246. LF      EQU     0AH
  247. EOM     EQU     0DH
  248. ESCAPE  EQU     27
  249. XON     EQU     17
  250. XOFF    EQU     19
  251.  
  252. TOP_BORDER      DB    "╔═════════════════ OUT ════════════════╗╔═════════════════ IN ═════════════════╗$"
  253. BOT_BORDER      DB    "╚══════════════════════════════════════╝╚══════════════════════════════════════╝$"
  254. VERT_BORDER     DB    "║$"
  255. INTRO           DB    "CHAT MODE: Type anything.  ENTER sends each message.  Hit ESC to exit.$"
  256. FULL_QUEUE      DB    "Warning: The transmission queue is full.  Please hit ENTER to end the message.$"
  257. INVALID_MSG     DB    "Warning: Invalid key was depressed.$"
  258. TX_POSITION     DW    ?
  259. RX_POSITION     DW    ?
  260. VT_POSITION     DW    0
  261. LMSG            DW    0
  262. VECTOR_SEG      DW    ?
  263. VECTOR_OFF      DW    ?
  264. MODE            DB    ?                 ;Mode = 3 for VT52 emulation, 1 for CHAT
  265. STATUS          DB    "STATUS:    Baud: 1200    Parity: N    Data Bits: 8    Stop Bit(s): 1$"
  266. APPLICATION     DB    0                 ;Indicates numeric keypad application mode.
  267. ESC_SEQ         DB    0
  268. DCADDRESS_LINE  DB    ?
  269. COMM_PAR        DB    10000011B         ;Communications parameters
  270. BAUD_PROMPT     DB    "Select Baud:  A)110  B)150  C)300  D)600  E)1200  F)2400  G)4800  H)9600  $"
  271. PARITY_PROMPT   DB    "Select Parity:  N)one  E)ven  O)dd                                        $"
  272. DATA_PROMPT     DB    "Select Data Bits:  7)Seven  8)Eight                                       $"
  273. STOP_PROMPT     DB    "Select Stop Bits:  1)One  2)Two                                           $"
  274. XOFF_MSG        DB    "Receiced XOFF.  Please stop typing.$"
  275. FLOW            DB    0
  276.  
  277. ;       Call subroutines.
  278.  
  279. OLA:    CALL    ISR_INIT                ;Install new interupt service routine 0Ch
  280.  
  281. VT52:
  282.         MOV     MODE, 3                 ;Update mode indicator
  283.         CALL    PORT_INIT
  284.         CALL    VT52_SCREEN
  285.         CALL    CLEAR_QUEUES
  286.  
  287. EMU:    CALL    VT52_INPUT
  288.         CMP     AL, 0                   ;Could character be for program control?
  289.         JNE     NO_ALT
  290.         CMP     AH, 24                  ;CHAT for Alt-O
  291.         JE      CHAT
  292.         CMP     AH, 45                  ;Exit to DOS for Alt-X
  293.         JE      CIAO
  294.  
  295. NO_ALT: CALL    VT52_DISPLAY
  296.         CALL    FLOW_CONTROL            ;Handle receipt of XOFF.
  297.  
  298.         JMP     EMU
  299.  
  300. CHAT:
  301.         MOV     MODE, 1                 ;Update mode indicator
  302.         CALL    PORT_INIT
  303.         CALL    CHAT_SCREEN
  304.         CALL    CLEAR_QUEUES
  305.  
  306. GAB:    CALL    CHAT_INPUT              ;Process characters in keyboard buffer
  307.         CMP     AL, ESCAPE              ;If escape entered, exit
  308.         JE      VT52
  309.  
  310.         CALL    RX_DISPLAY              ;Display any received character
  311.  
  312.         JMP     GAB                     ;Repeat for next character
  313.  
  314. CIAO:
  315.         SCROLL_UP   0, 0, 0, 24, 79     ;Blank screen upon exit
  316.  
  317.         MOV     DX, VECTOR_OFF
  318.         MOV     DS, VECTOR_SEG
  319.         MOV     AX, 250CH               ;Install original interrupt vector
  320.         INT     21H
  321.  
  322.         MOV     AH,4Ch                  ;DOS code to exit
  323.         INT     21h                     ;(exit)
  324.  
  325. MAIN    ENDP
  326.  
  327. ;===============================================================================
  328. ;
  329. ;       ISR_INIT Subroutine:
  330. ;
  331. ;       Installs new INT 0Ch vector.  Saves original vector for restoration.
  332. ;
  333. ;===============================================================================
  334.  
  335. ISR_INIT   PROC NEAR
  336.  
  337.         PUSH    AX
  338.         PUSH    BX
  339.         PUSH    DX
  340.         PUSH    ES
  341.  
  342.         MOV     AX, 350CH               ;Get original INT 0Ch vector
  343.         INT     21H
  344.         MOV     VECTOR_SEG, ES
  345.         MOV     VECTOR_OFF, BX
  346.  
  347.         LEA     DX, ISR0C               ;Find address of new interupt service routine
  348.         MOV     AX, 250CH               ;Install vector for new ISR
  349.         INT     21H
  350.  
  351.         POP     ES
  352.         POP     DX
  353.         POP     BX
  354.         POP     AX
  355.  
  356.         RET
  357.  
  358. ISR_INIT   ENDP
  359.  
  360. ;===============================================================================
  361. ;
  362. ;       ISR0C   Interupt Handler:
  363. ;
  364. ;       Alerted by interupt type 0Ch.  Checks for type of UART interupt, and
  365. ;       acts accordingly.  If RDA is true, reads character from UART.  If THRE
  366. ;       is true, transmits character from TX queue.
  367. ;
  368. ;===============================================================================
  369.  
  370. ISR0C   PROC
  371.  
  372.         PUSH    AX
  373.         PUSH    DX
  374.         PUSH    DI
  375.         PUSH    DS
  376.  
  377.         MOV     AX, CSEG                ;Restore data segment register
  378.         MOV     DS, AX
  379.  
  380.         MOV     DX, 03FAH               ;Check Interupt
  381.         IN      AL, DX                  ;Identification Register
  382.         TEST    AL, 10B                 ;Was it a THRE irpt?
  383.         JNZ     THRE
  384.  
  385.         MOV     DX, 3F8H                ;Receive character
  386.         IN      AL, DX
  387.  
  388.         CMP     AL, XOFF                ;Check for XOFF
  389.         JNE     ISR1
  390.         MOV     FLOW, 0FFH              ;Set data flow indicator
  391.         JMP     ISR_DONE
  392.  
  393. ISR1:   CMP     AL, XON                 ;Check for XON
  394.         JNE     ISR2
  395.         MOV     FLOW, 0                 ;Reset data flow indicator
  396.         JMP     ISR_DONE
  397.  
  398. ISR2:   LEA     DI, RQ
  399.         CALL    ENQUEUE                 ;Enqueue received character
  400.         JMP     ISR_DONE
  401.  
  402. THRE:
  403.         LEA     DI, TQ                  ;Dequeue character for transmission
  404.         CALL    DEQUEUE
  405.         MOV     DX, 03F8H               ;Transmit character
  406.         OUT     DX, AL
  407.  
  408.         CMP     MODE, 1                 ;Disable THRE according to mode
  409.         JE      CHATTER
  410.         CMP     TQ.COUNT, 0             ;Any characters to be sent?
  411.         JNE     ISR_DONE
  412.         MOV     AL, 01B                 ;If not, disable THRE irpts
  413.         MOV     DX, 03F9H
  414.         OUT     DX, AL
  415.         JMP     ISR_DONE
  416.  
  417. CHATTER:
  418.         CMP     TQ.NMSGS, 0             ;Any more pending messages to be sent?
  419.         JNE     ISR_DONE
  420.         MOV     AL, 01B                 ;If no more messages pending,
  421.         MOV     DX, 03F9H               ;disable THRE irpts
  422.         OUT     DX, AL
  423.  
  424. ISR_DONE:
  425.         MOV     AL, 20H                 ;Inform UART that ISR is finished
  426.         OUT     20H, AL
  427.  
  428.  
  429.         POP     DS
  430.         POP     DI
  431.         POP     DX
  432.         POP     AX
  433.         IRET
  434.  
  435. ISR0C   ENDP
  436.  
  437. ;===============================================================================
  438. ;
  439. ;       PORT_INIT Subroutine:
  440. ;
  441. ;       Initializes primary serial port for the parameters determined by AL.
  442. ;
  443. ;       Uses BIOS function INT 14h, Subfunction 0.
  444. ;
  445. ;       Input:  COMM_PAR has initialization bit pattern: BBBPPSLL
  446. ;
  447. ;       Output: COM1 is initialized
  448. ;               ALL REGISTERS PRESERVED
  449. ;
  450. ;===============================================================================
  451.  
  452. PORT_INIT       PROC    NEAR
  453.  
  454.         PUSH    AX
  455.         PUSH    DX
  456.  
  457.         MOV     DX, 0                   ;Choose primary port
  458.         MOV     AH, 0                   ;Indicate subfunction
  459.         MOV     AL, COMM_PAR            ;Get communication parameters
  460.         INT     14H                     ;Initialize port
  461.  
  462.         MOV     DX, 3FDH                ;Clear out any initial garbage
  463.         IN      AL, DX                  ;in UART register
  464.         TEST    AL, 1B
  465.         JE      PORT_CLEAR
  466.  
  467.         MOV     DX, 3F8H                ;Receive garbage character
  468.         IN      AL, DX
  469.  
  470. PORT_CLEAR:
  471.         MOV     AL, 01B
  472.         MOV     DX, 03F9H
  473.         OUT     DX, AL                  ;Enable RDA irpts
  474.  
  475.         MOV     AL, 1011B               ;Set OUT2 of the Modem Control Register
  476.         MOV     DX, 03FCH               ;so UART passes Irpts to the 8259
  477.         OUT     DX, AL                  ;Also, initiate handshaking through DTR and RTS
  478.  
  479. SHAKE:  MOV     DX, 03FEH               ;Check that modem has completed handshake
  480.         IN      AL, DX
  481.         AND     AL, 00110000B           ;Is modem ready to communicate?
  482.         JZ      SHAKE                   ;If not, wait
  483.  
  484.         IN      AL, 21H                 ;Enable IRQ4 interrupts at
  485.         AND     AL, 11101111B           ;the 8259 PIC
  486.         OUT     21H, AL
  487.  
  488.         POP     DX
  489.         POP     AX
  490.  
  491.         RET
  492.  
  493. PORT_INIT       ENDP
  494.  
  495. ;===============================================================================
  496. ;
  497. ;       VT52_SCREEN Subroutine:
  498. ;
  499. ;       Displays status line and positions cursor for VT52 emulation.
  500. ;
  501. ;===============================================================================
  502.  
  503. VT52_SCREEN     PROC   NEAR
  504.  
  505.         PUSH    DX
  506.  
  507.         SCROLL_UP  0, 0, 0, 24, 79
  508.         MOV     DX, 1800H
  509.         LOCATE
  510.         DISPLAY STATUS
  511.         MOV     DX, VT_POSITION
  512.         LOCATE
  513.  
  514.         POP     DX
  515.         RET
  516.  
  517. VT52_SCREEN     ENDP
  518.  
  519. ;===============================================================================
  520. ;
  521. ;       VT52_INPUT Subroutine:
  522. ;
  523. ;       Uses BIOS function INT 16h to check for and retrieve characters typed
  524. ;       on transmitting keyboard.  Queues them into TQ.
  525. ;
  526. ;===============================================================================
  527.  
  528. VT52_INPUT      PROC  NEAR
  529.  
  530.         PUSH    BX
  531.         PUSH    DI
  532.  
  533.         MOV     AH, 1
  534.         INT     16H
  535.         JZ      VTI_RESET
  536.  
  537.         MOV     AH, 0                   ;Accept character from keyboard
  538.         INT     16H
  539.  
  540.         CMP     AL, 0                   ;Convert special keys, and flag invalid keys
  541.         JNE     VT_IN1
  542.         CALL    VT52_SPECIAL
  543.         CMP     AL, 0                   ;Don't enqueue invalid characters
  544.         JE      DONE_IN2
  545.  
  546. VT_IN1: CMP     APPLICATION, 0          ;Is keypad in application mode?
  547.         JE      VT_IN2
  548.         MOV     BL, AL                  ;If so, add 40 to ASCII value of
  549.         MOV     BH, 0                   ;keypad characters as part of
  550.         ADD     AL, APP_CODES[BX]       ;VT52 specs
  551.         PUSH    AX
  552.         MOV     AL, ESCAPE              ;Send ESC ? before application
  553.         LEA     DI, TQ                  ;keypad value
  554.         CALL    ENQUEUE
  555.         MOV     AL, "?"
  556.         CALL    ENQUEUE
  557.         POP     AX
  558.  
  559. VT_IN2: LEA     DI, TQ                  ;Enqueue character for transmission
  560.         CALL    ENQUEUE
  561.         PUSH    AX
  562.         MOV     AL, 11B                 ;Enable THRE irpts, as character(s)
  563.         MOV     DX, 03F9H               ;wait for transmission
  564.         OUT     DX, AL
  565.         POP     AX
  566.         JMP     DONE_IN2
  567.  
  568. VTI_RESET:
  569.         MOV     AX, 0                   ;If no key entered reset "new key value"
  570.  
  571. DONE_IN2:
  572.         POP     DI
  573.         POP     BX
  574.         RET
  575.  
  576. VT52_INPUT      ENDP
  577.  
  578. APP_CODES       DB  12 DUP(0), 40H, 30 DUP(0), 3 DUP(40H), 0, 10 DUP(40H), 200 DUP(0)
  579.  
  580. ;===============================================================================
  581. ;
  582. ;       VT52_SPECIAL Subroutine:
  583. ;
  584. ;       Interprets cursor movement and screen control keys.
  585. ;       Transmits appropriate escape sequence.
  586. ;
  587. ;===============================================================================
  588.  
  589. VT52_SPECIAL    PROC   NEAR
  590.  
  591.         PUSH    BX
  592.         PUSH    DX
  593.         PUSH    DI
  594.  
  595.         CMP     AH, 25                  ;Change comm. parameters?
  596.         JNE     SPEC1
  597.         CALL    LINE_SETTINGS
  598.         JMP     FINI
  599.  
  600. SPEC1:  CMP     AH, 59                  ;Don't interpret invalid key press
  601.         JB      FINI
  602.         CMP     AH, 118
  603.         JA      FINI
  604.  
  605.         MOV     BL, AH                  ;Use look-up table of appropriate sequences
  606.         MOV     BH, 0
  607.         SUB     BX, 50
  608.         MOV     DL, SPECIAL_CODES[BX]
  609.         CMP     DL, " "                 ;Don't interpret invalid keys
  610.         JE      FINI
  611.  
  612.         MOV     AL, DL                  ;Get ready for enqueuing sequences
  613.         PUSH    AX
  614.         LEA     DI, TQ
  615.  
  616.         CMP     AL, "J"                 ;Was it CLEAR SCREEN?
  617.         JNE     SPEC2
  618.         MOV     AL, ESCAPE              ;CLEAR SCREEN is a dual escape sequence
  619.         CALL    ENQUEUE
  620.         MOV     AL, "H"
  621.         CALL    ENQUEUE
  622.  
  623. SPEC2:  MOV     AL, ESCAPE              ;Enqueue esc of sequence
  624.         CALL    ENQUEUE
  625.         POP     AX
  626.  
  627. FINI:   POP     DI
  628.         POP     DX
  629.         POP     BX
  630.         RET
  631.  
  632. VT52_SPECIAL    ENDP
  633.  
  634. SPECIAL_CODES   DB     "         PQRS        HA  D C KB                                     J"
  635.  
  636. ;===============================================================================
  637. ;
  638. ;       VT52_DISPLAY Subroutine:
  639. ;
  640. ;       Interprets and displays received characters.
  641. ;
  642. ;===============================================================================
  643.  
  644. VT52_DISPLAY    PROC   NEAR
  645.  
  646.         PUSH    AX
  647.         PUSH    BX
  648.         PUSH    DX
  649.         PUSH    DI
  650.  
  651.         CMP     RQ.COUNT, 0             ;Received characters for display?
  652.         JE      VTD_DONE
  653.  
  654.         LEA     DI, RQ                  ;Dequeue next available character
  655.         CALL    DEQUEUE
  656.  
  657.         CMP     ESC_SEQ, 0              ;Part of esc sequence?
  658.         JE      VTD1
  659.         CALL    VTD_ESCAPE
  660.         JMP     VTD_DONE
  661.  
  662. VTD1:   CMP     AL, ESCAPE              ;Is character start of escape sequence?
  663.         JNE     VTD2
  664.         MOV     ESC_SEQ, 0FFH           ;Store escape sequence status
  665.         JMP     VTD_DONE
  666.  
  667. VTD2:   MOV     DX, VT_POSITION         ;Position cursor
  668.         LOCATE
  669.         MOV     AH, 2                   ;Display new character
  670.         MOV     DL, AL
  671.         INT     21H
  672.  
  673.         MOV     AH, 3                   ;Determine new cursor location
  674.         MOV     BH, 0
  675.         INT     10H
  676.         CMP     DH, 24                  ;Is cursor on status line?
  677.         JNE     VTD3
  678.         SCROLL_UP   1, 0, 0, 23, 79     ;Scroll if necessary
  679.         MOV     DH, 23
  680.         LOCATE
  681.  
  682. VTD3:   MOV     VT_POSITION, DX         ;Store new cursor location
  683.  
  684. VTD_DONE:
  685.         POP     DI
  686.         POP     DX
  687.         POP     BX
  688.         POP     AX
  689.         RET
  690.  
  691. VT52_DISPLAY    ENDP
  692.  
  693. ;===============================================================================
  694. ;
  695. ;       VTD_ESCAPE   Subroutine:
  696. ;
  697. ;       Moves cursor and/or manipulate screen according to escape sequence.
  698. ;
  699. ;===============================================================================
  700.  
  701. VTD_ESCAPE      PROC   NEAR
  702.  
  703.         PUSH    AX
  704.         PUSH    DX
  705.  
  706.         CMP     ESC_SEQ, 0FFH           ;Initial character after escape received?
  707.         JE      VE1                     ;Yes, jump to code for simple sequences
  708.  
  709.         CMP     ESC_SEQ, 0FH            ;Final character of Direct Cursor Address?
  710.         JE      VE2                     ;Yes
  711.         SUB     AL, 20H                 ;No, calculate specified line for LOCATE macro
  712.         CMP     AL, 23                  ;Check to see line is on screen
  713.         JBE     VE3
  714.         MOV     AL, 23
  715. VE3:    MOV     DCADDRESS_LINE, AL      ;Store lin specified by DCA
  716.         MOV     ESC_SEQ, 0FH
  717.         JMP     VE_DONE
  718.  
  719. VE2:    SUB     AL, 20H                 ;Interpret column of DCA
  720.         CMP     AL, 79
  721.         JBE     VE4
  722.         MOV     AL, 79
  723. VE4:    MOV     DL, AL
  724.         MOV     DH, DCADDRESS_LINE
  725.         JMP     VE_LOC                  ;Locate cursor
  726.  
  727. VE1:    MOV     DX, VT_POSITION         ;Interpret simple escape sequences
  728.         CMP     AL, "A"                 ;Up arrow?
  729.         JNE     VE5
  730.         CMP     DH, 0
  731.         JE      VE_RESET
  732.         DEC     DH
  733.         JMP     VE_LOC
  734.  
  735. VE5:    CMP     AL, "B"                 ;Down arrow?
  736.         JNE     VE6
  737.         CMP     DH, 23
  738.         JE      VE_RESET
  739.         INC     DH
  740.         JMP     VE_LOC
  741.  
  742. VE6:    CMP     AL, "C"                 ;Right arrow?
  743.         JNE     VE7
  744.         CMP     DL, 79
  745.         JE      VE_RESET
  746.         INC     DL
  747.         JMP     VE_LOC
  748.  
  749. VE7:    CMP     AL, "D"                 ;Left arrow?
  750.         JNE     VE8
  751.         CMP     DL, 0
  752.         JE      VE_RESET
  753.         DEC     DL
  754.         JMP     VE_LOC
  755.  
  756. VE8:    CMP     AL, "H"                 ;Home cursor?
  757.         JNE     VE9
  758.         MOV     DX, 0
  759.         JMP     VE_LOC
  760.  
  761. VE9:    CMP     AL, "I"                 ;Reverse Line feed?
  762.         JNE     VE10
  763.         CMP     DH, 0
  764.         JE      ROOM
  765.         DEC     DH
  766.         JMP     VE_LOC
  767. ROOM:   SCROLL_DOWN    1, 0, 0, 23, 79
  768.         JMP     VE_LOC
  769.  
  770. VE_RESET:                               ;Reset escape sequence indicator
  771.         MOV     ESC_SEQ, 0
  772.         JMP     VE_DONE
  773.  
  774. VE10:   CMP     AL, "J"                 ;Erase EOS?
  775.         JNE     VE11
  776.         CMP     DH, 23
  777.         JE      VE12
  778.         CALL    CLEAR_BLOCK
  779. VE12:   CALL    ERASE_EOL
  780.         JMP     VE_LOC
  781.  
  782. VE11:   CMP     AL, "K"                 ;Erase EOL?
  783.         JNE     VE13
  784.         CALL    ERASE_EOL
  785.         JMP     VE_LOC
  786.  
  787. VE13:   CMP     AL, "Y"                 ;Direct Cursor Address?
  788.         JNE     VE14
  789.         MOV     ESC_SEQ, 0F0H
  790.         JMP     VE_DONE
  791.  
  792. VE14:   CMP     AL, "Z"                 ;Identify Terminal?
  793.         JNE     VE15
  794.         CALL    IDENTIFY
  795.         JMP     VE_RESET
  796.  
  797. VE15:   CMP     AL, "="                 ;Enter Application Keypad Mode?
  798.         JNE     VE16
  799.         MOV     APPLICATION, 0FFH
  800.         JMP     VE_RESET
  801.  
  802. VE16:   CMP     AL, ">"                 ;Exit App Keypad Mode?
  803.         JNE     VE_RESET
  804.         MOV     APPLICATION, 0
  805.         JMP     VE_RESET
  806.  
  807.  
  808. VE_LOC: LOCATE                          ;Reposition cursor
  809.         MOV     VT_POSITION, DX
  810.         JMP     VE_RESET
  811.  
  812. VE_DONE:
  813.         POP     DX
  814.         POP     AX
  815.         RET
  816.  
  817. VTD_ESCAPE      ENDP
  818.  
  819. ;===============================================================================
  820. ;
  821. ;       CLEAR_BLOCK Subroutine:
  822. ;
  823. ;       Erases screen below cursor as part of ERASE EOS.
  824. ;       Uses INT 10, Sub 6 to scroll block.
  825. ;
  826. ;===============================================================================
  827.  
  828. CLEAR_BLOCK     PROC   NEAR
  829.  
  830.         PUSH    AX
  831.         PUSH    BX
  832.         PUSH    CX
  833.         PUSH    DX
  834.  
  835.         MOV     AH, 6                   ;Choose subfunction
  836.         MOV     AL, 0                   ;Load parameters
  837.         MOV     BH, 7
  838.         MOV     CH, DH
  839.         INC     CH
  840.         MOV     CL, 0
  841.         MOV     DX, 174FH
  842.         INT     10H                     ;Erase block
  843.  
  844.         POP     DX
  845.         POP     CX
  846.         POP     BX
  847.         POP     AX
  848.         RET
  849.  
  850. CLEAR_BLOCK     ENDP
  851.  
  852. ;===============================================================================
  853. ;
  854. ;       ERASE_EOL   Subroutine:
  855. ;
  856. ;       Erases screen to end of current line.
  857. ;       Uses INT 10, Sub 6 to scroll line.
  858. ;
  859. ;================================================================================
  860.  
  861. ERASE_EOL       PROC   NEAR
  862.  
  863.         PUSH    AX
  864.         PUSH    BX
  865.         PUSH    CX
  866.         PUSH    DX
  867.  
  868.         MOV     AH, 6                   ;Choose subfunction
  869.         MOV     AL, 0                   ;Load parameters
  870.         MOV     BH, 7
  871.         MOV     CX, DX
  872.         MOV     DL, 79
  873.         INT     10H                     ;Erase block
  874.  
  875.         POP     DX
  876.         POP     CX
  877.         POP     BX
  878.         POP     AX
  879.         RET
  880.  
  881. ERASE_EOL       ENDP
  882.  
  883. ;===============================================================================
  884. ;
  885. ;       IDENTIFY    Subroutine:
  886. ;
  887. ;       Sends remote computer identifying string unique to VT52: esc / Z
  888. ;
  889. ;===============================================================================
  890.  
  891. IDENTIFY        PROC   NEAR
  892.  
  893.         PUSH    AX
  894.         PUSH    DI
  895.  
  896.         LEA     DI, TQ
  897.         MOV     AL, ESCAPE              ;Send esc
  898.         CALL    ENQUEUE
  899.  
  900.         MOV     AL, "/"                 ;Send /
  901.         CALL    ENQUEUE
  902.  
  903.         MOV     AL, "Z"                 ;Send Z
  904.         CALL    ENQUEUE
  905.  
  906.         POP     DI
  907.         POP     AX
  908.         RET
  909.  
  910. IDENTIFY        ENDP
  911.  
  912. ;===============================================================================
  913. ;
  914. ;       LINE_SETTINGS  Subroutine:
  915. ;
  916. ;       Allows user to alter communication parameters.  UART is reset,
  917. ;       and status line updated.
  918. ;
  919. ;===============================================================================
  920.  
  921. LINE_SETTINGS   PROC   NEAR
  922.  
  923.         PUSH    AX
  924.         PUSH    BX
  925.         PUSH    DX
  926.  
  927.         MOV     DX, 1800H               ;Prompt user for BAUD
  928.         LOCATE
  929.         DISPLAY BAUD_PROMPT
  930. LS1:    MOV     AH, 8
  931.         INT     21H                     ;Get response
  932.         CMP     AL, 97
  933.         JB      CAPS
  934.         SUB     AL, 32
  935. CAPS:   SUB     AL, 65
  936.         CMP     AL, 7
  937.         JA      LS1
  938.         MOV     BH, 0
  939.         MOV     BL, AL
  940.         SHL     BL, 1
  941.         MOV     DX, BAUD[BX]
  942.         BIN2ASCII   4, STATUS[17]       ;Update status line
  943.         SHL     AL, 1                   ;Update parameters for UART
  944.         SHL     AL, 1
  945.         SHL     AL, 1
  946.         SHL     AL, 1
  947.         SHL     AL, 1
  948.         MOV     COMM_PAR, AL
  949.  
  950.         MOV     DX, 1800H               ;Prompt user for PARITY
  951.         LOCATE
  952.         DISPLAY PARITY_PROMPT
  953. LS2:    MOV     AH, 8                   ;get response
  954.         INT     21H
  955.         CMP     AL, 97                  ;Interpret choice
  956.         JB      CAPS2
  957.         SUB     AL, 32
  958. CAPS2:  CMP     AL, "E"
  959.         JE      LS3
  960.         CMP     AL, "O"
  961.         JE      LS4
  962.         CMP     AL, "N"
  963.         JE      LS5
  964.         JMP     LS2
  965. LS3:    OR      COMM_PAR, 00011000B     ;Update UART parameters
  966. LS4:    OR      COMM_PAR, 00001000B
  967. LS5:    MOV     STATUS[33], AL
  968.  
  969.         MOV     DX, 1800H               ;Prompt user for data bits
  970.         LOCATE
  971.         DISPLAY DATA_PROMPT
  972. LS6:    MOV     AH, 8                   ;Get response
  973.         INT     21H
  974.         CMP     AL, "8"
  975.         JE      LS7
  976.         CMP     AL, "7"
  977.         JE      LS8
  978.         JMP     LS6
  979. LS7:    OR      COMM_PAR, 11B
  980. LS8:    OR      COMM_PAR, 10B
  981.         MOV     STATUS[49], AL
  982.  
  983.         MOV     DX, 1800H               ;Prompt user for stop bits
  984.         LOCATE
  985.         DISPLAY STOP_PROMPT
  986. LS9:    MOV     AH, 8
  987.         INT     21H                     ;Get response
  988.         CMP     AL, "2"
  989.         JE      LS10
  990.         CMP     AL, "1"
  991.         JE      LS11
  992.         JMP     LS9
  993. LS10:   OR      COMM_PAR, 100B
  994. LS11:   MOV     STATUS[67], AL
  995.  
  996.         MOV     DX, 1800H               ;Display new status
  997.         LOCATE
  998.         DISPLAY STATUS
  999.         MOV     DX, VT_POSITION
  1000.         LOCATE
  1001.  
  1002.         CALL    PORT_INIT               ;Reinitialize UART
  1003.  
  1004.         POP     DX
  1005.         POP     BX
  1006.         POP     AX
  1007.  
  1008.         RET
  1009.  
  1010. LINE_SETTINGS   ENDP
  1011.  
  1012. BAUD    DW      110, 150, 300, 600, 1200, 2400, 4800, 9600
  1013.  
  1014. ;===============================================================================
  1015. ;
  1016. ;       FLOW_CONTROL Subroutine:
  1017. ;
  1018. ;       Implementation of XON/XOFF protocol.
  1019. ;
  1020. ;       If XOFF received, informs user and waits for receipt of XON
  1021. ;       before further transmission.
  1022. ;
  1023. ;===============================================================================
  1024.  
  1025. FLOW_CONTROL    PROC   NEAR
  1026.  
  1027.         PUSH    DX
  1028.  
  1029.         CMP     FLOW, 0                 ;XOFF received?
  1030.         JE      FC_DONE
  1031.  
  1032.         MOV     DX, 1800H
  1033.         LOCATE
  1034.         DISPLAY XOFF_MSG                ;Inform user of receipt
  1035.  
  1036. FC1:    CMP     FLOW, 0FFH              ;Wait for XON
  1037.         JE      FC1
  1038.  
  1039.         LOCATE                          ;Refresh status line
  1040.         DISPLAY STATUS
  1041.  
  1042. FC_DONE:  POP   DX
  1043.         RET
  1044.  
  1045. FLOW_CONTROL    ENDP
  1046.  
  1047. ;===============================================================================
  1048. ;
  1049. ;       CHAT_SCREEN Subroutine:
  1050. ;
  1051. ;       Displays windows for transmission and reception of characters.
  1052. ;
  1053. ;       Uses the DISPLAY macro to display border elements, the LOCATE macro to
  1054. ;       position cursor, and the SCROLL_UP macro to clear the screen.
  1055. ;
  1056. ;===============================================================================
  1057.  
  1058. CHAT_SCREEN     PROC    NEAR
  1059.  
  1060.         PUSH    CX
  1061.         PUSH    DX
  1062.  
  1063.         SCROLL_UP   0, 0, 0, 24, 79     ;Blank screen initially
  1064.  
  1065.         MOV     DX, 0
  1066.         LOCATE                          ;Position top border
  1067.         DISPLAY TOP_BORDER
  1068.  
  1069.         MOV     DH, 23                  ;Position bottom border
  1070.         LOCATE
  1071.         DISPLAY BOT_BORDER
  1072.  
  1073.         MOV     CX, 22                  ;Draw vertical borders down 22 rows
  1074.  
  1075. ROW:    MOV     DH, CL
  1076.  
  1077.         MOV     DL, 0
  1078.         LOCATE
  1079.         DISPLAY VERT_BORDER
  1080.  
  1081.         MOV     DL, 39
  1082.         LOCATE
  1083.         DISPLAY VERT_BORDER
  1084.  
  1085.         MOV     DL, 40
  1086.         LOCATE
  1087.         DISPLAY VERT_BORDER
  1088.  
  1089.         MOV     DL, 79
  1090.         LOCATE
  1091.         DISPLAY VERT_BORDER
  1092.  
  1093.         LOOP    ROW
  1094.  
  1095.         MOV     DX, 1800H               ;Greet user
  1096.         LOCATE
  1097.         DISPLAY INTRO
  1098.  
  1099.         MOV     TX_POSITION, 0101H
  1100.         MOV     RX_POSITION, 0129H
  1101.         MOV     DX, 0101H
  1102.         LOCATE
  1103.  
  1104.         POP     DX
  1105.         POP     CX
  1106.  
  1107.         RET
  1108.  
  1109. CHAT_SCREEN     ENDP
  1110.  
  1111. ;===============================================================================
  1112. ;
  1113. ;       CHAT_INPUT  Subroutine:
  1114. ;
  1115. ;       Uses BIOS function INT 16h to check for and retrieve characters typed
  1116. ;       on transmitting keyboard.
  1117. ;
  1118. ;       Output: AL = character typed, or 0 for invalid character
  1119. ;               AH DESTROYED
  1120. ;
  1121. ;===============================================================================
  1122.  
  1123. CHAT_INPUT      PROC  NEAR
  1124.  
  1125.         PUSH    DX
  1126.         PUSH    DI
  1127.  
  1128.         MOV     AH, 1
  1129.         INT     16H
  1130.         JZ      DONE_IN
  1131.  
  1132.         SCROLL_UP  0, 24, 0, 24, 79     ;Clear status line
  1133.  
  1134.         MOV     AH, 0                   ;Accept character from keyboard
  1135.         INT     16H
  1136.  
  1137.         CMP     AL, ESCAPE                 ;Exit for ESC
  1138.         JE      DONE_IN
  1139.  
  1140.         CMP     AL, 0                   ;Convert cursor keys, and flag invalid keys
  1141.         JNE     CHAR_ENQ
  1142.         CALL    CURSOR_KEY
  1143.         CMP     AL, 0                   ;Don't enqueue invalid characters
  1144.         JE      DONE_IN
  1145.  
  1146. CHAR_ENQ:
  1147.         CMP     AL, 9                   ;Convert tabs to spaces
  1148.         JNE     DETABBED
  1149.         MOV     AL, 32
  1150.  
  1151. DETABBED:
  1152.         LEA     DI, TQ                  ;Enqueue character for transmission
  1153.         CALL    ENQUEUE
  1154.         JC      QUEUE_ERROR             ;Alert user of full queue
  1155.  
  1156.         CMP     AL, EOM
  1157.         JNE     TX_SHOW
  1158.         PUSH    AX
  1159.         MOV     AL, 11B
  1160.         MOV     DX, 03F9H
  1161.         OUT     DX, AL
  1162.         POP     AX
  1163.  
  1164. TX_SHOW:
  1165.         CALL    TX_DISPLAY              ;Display characters
  1166.  
  1167. DONE_IN:
  1168.         POP     DI
  1169.         POP     DX
  1170.         RET
  1171.  
  1172. QUEUE_ERROR:                            ;Display warning and instruction to user
  1173.         MOV     DX, 1800H
  1174.         LOCATE
  1175.         DISPLAY FULL_QUEUE
  1176.         JMP     DONE_IN
  1177.  
  1178. CHAT_INPUT      ENDP
  1179.  
  1180. ;===============================================================================
  1181. ;
  1182. ;       CURSOR_KEY Subroutine:
  1183. ;
  1184. ;       Converts cursor-movement-key scan codes into unused ASCII values
  1185. ;       for display and transmission.  Also alerts user of invalid key
  1186. ;       entries.  Uses DISPLAY and LOCATE macros to display message.
  1187. ;
  1188. ;       Input:  AH = scan code to be converted.
  1189. ;
  1190. ;       Output: AL = ASCII value
  1191. ;
  1192. ;===============================================================================
  1193.  
  1194. CURSOR_KEY      PROC    NEAR
  1195.  
  1196.         CMP     AH, 72                  ;Up arrow?
  1197.         JE      UP_TX
  1198.         CMP     AH, 75                  ;Left arrow?
  1199.         JE      LEFT_TX
  1200.         CMP     AH, 77                  ;Right arrow?
  1201.         JE      RIGHT_TX
  1202.         CMP     AH, 80                  ;Down arrow?
  1203.         JE      DOWN_TX
  1204.  
  1205.         MOV     AL, 0
  1206.         MOV     DX, 1800H
  1207.         LOCATE
  1208.         DISPLAY INVALID_MSG             ;All other special keys are invalid
  1209.         RET
  1210.  
  1211. UP_TX:  MOV     AL, 30                  ;Convert cursor keys to
  1212.         RET                             ;unused ASCII values
  1213.  
  1214. LEFT_TX: MOV    AL, 29
  1215.          RET
  1216.  
  1217. RIGHT_TX: MOV   AL, 28
  1218.           RET
  1219.  
  1220. DOWN_TX: MOV    AL, 31
  1221.          RET
  1222.  
  1223. CURSOR_KEY      ENDP
  1224.  
  1225. ;===============================================================================
  1226. ;
  1227. ;       TX_DISPLAY Subroutine:
  1228. ;
  1229. ;       Displays characters typed into keyboard for transmission.   Uses DOS
  1230. ;       function 2, as well as LOCATE and SCROLL_UP macros for display.
  1231. ;       BIOS INT 10, subfunction 3 used to determine cursor location.
  1232. ;
  1233. ;===============================================================================
  1234.  
  1235. TX_DISPLAY      PROC    NEAR
  1236.  
  1237.         PUSH    AX
  1238.         PUSH    BX
  1239.         PUSH    CX
  1240.         PUSH    DX
  1241.  
  1242.         MOV     DX, TX_POSITION         ;Position cursor properly in OUT window
  1243.  
  1244. ;Interpret cursor movement keys
  1245.  
  1246.         CMP     AL, 8                   ;Backspace?
  1247.         JE      TD_LEFT
  1248.  
  1249.         CMP     AL, 29                  ;Left arrow?
  1250.         JNE     TD_NL
  1251. TD_LEFT: CMP     DL, 1
  1252.         JE      TD_STEP
  1253.         DEC     DL
  1254.         LOCATE
  1255.         JMP     TD_SAVE
  1256.  
  1257. TD_NL:  CMP     AL, 28                  ;Right arrow?
  1258.         JNE     TD_NR
  1259.         CMP     DL, 38
  1260.         JE      TD_STEP
  1261.         INC     DL
  1262.         LOCATE
  1263.         JMP     TD_SAVE
  1264.  
  1265. TD_NR:  CMP     AL, 30                  ;Up arrow?
  1266.         JNE     TD_NU
  1267.         CMP     DH, 1
  1268.         JE      TD_STEP
  1269.         DEC     DH
  1270.         LOCATE
  1271.         JMP     TD_SAVE
  1272.  
  1273. TD_STEP:    LOCATE                      ;Used to facilitate long range, conditional jumps
  1274.         JMP TD_DONE
  1275.  
  1276. TD_NU:  CMP     AL, 31                  ;Down arrow?
  1277.         JNE     TD_ND
  1278. TD_DOWN:        CMP     DH, 22
  1279.         JE      TD_BOTTOM
  1280.         INC     DH
  1281.         LOCATE
  1282.         JMP     TD_SAVE
  1283. TD_BOTTOM:    SCROLL_UP 1, 1, 1, 22, 38 ;Scroll window 1 line if neccessary
  1284.         LOCATE
  1285.         JMP     TD_DONE
  1286.  
  1287. TD_ND:  CMP     AL, CR                  ;Carriage return?
  1288.         JNE     TD_NC
  1289.         MOV     DL, 1
  1290.         JMP     TD_DOWN
  1291.  
  1292. TD_NC:  CMP     AL, LF                  ;Line feed? (interpret same as down arrow)
  1293.         JE      TD_DOWN
  1294.         CMP     AL, 0BH                 ;Vertical tab? (same as down arrow)
  1295.         JE      TD_DOWN
  1296.         CMP     AL, 0CH                 ;Form feed? (same as down arrow)
  1297.         JE      TD_DOWN
  1298.  
  1299. ;Display non-movement characters
  1300.         CMP     DL, 39                  ;Character on right edge of window?
  1301.         JNE     TD_SHOW
  1302.         MOV     DL, 1                   ;Wrap around to next line
  1303.         CMP     DH, 22
  1304.         JNE     TD_LINE
  1305.         SCROLL_UP     1, 1, 1, 22, 38   ;Scroll 1 line if neccessary
  1306.         JMP     TD_SHOW
  1307.  
  1308. TD_LINE:   INC     DH                   ;Move down a line
  1309. TD_SHOW:   LOCATE
  1310.         MOV     AH, 2
  1311.         MOV     DL, AL
  1312.         INT     21H                     ;Display Character
  1313.  
  1314.         MOV     AH, 3
  1315.         MOV     BH, 0
  1316.         INT     10H                     ;Determine location of cursor
  1317. TD_SAVE:
  1318.         MOV     TX_POSITION, DX         ;Store current location
  1319.  
  1320. TD_DONE:
  1321.         POP     DX
  1322.         POP     CX
  1323.         POP     BX
  1324.         POP     AX
  1325.         RET
  1326.  
  1327. TX_DISPLAY      ENDP
  1328.  
  1329. ;===============================================================================
  1330. ;
  1331. ;       RX_DISPLAY Subroutine:
  1332. ;
  1333. ;       Displays any messages received from serial port.   Uses DOS
  1334. ;       function 2, as well as LOCATE and SCROLL_UP macros for display.
  1335. ;       BIOS INT 10, subfunction 3 used to determine cursor location.
  1336. ;
  1337. ;===============================================================================
  1338.  
  1339. RX_DISPLAY      PROC    NEAR
  1340.  
  1341.         PUSH    AX
  1342.         PUSH    BX
  1343.         PUSH    CX
  1344.         PUSH    DX
  1345.         PUSH    DI
  1346.  
  1347.         CMP     RQ.NMSGS, 0             ;Pending messages for display?
  1348.         JNE     DEQUIT
  1349.         JMP     RD_DONE
  1350.  
  1351. DEQUIT: LEA     DI, RQ                  ;Dequeue next available character
  1352.         CALL    DEQUEUE
  1353.  
  1354.         MOV     DX, RX_POSITION         ;Position cursor properly in window
  1355.  
  1356. ;Interpret cursor movement keys
  1357.  
  1358.         CMP     AL, 8                   ;Backspace?
  1359.         JE      RD_LEFT
  1360.  
  1361.         CMP     AL, 29                  ;Left arrow?
  1362.         JNE     RD_NL
  1363. RD_LEFT: CMP     DL, 41
  1364.         JE      RD_STEP
  1365.         DEC     DL
  1366.         LOCATE
  1367.         JMP     RD_SAVE
  1368.  
  1369. RD_NL:  CMP     AL, 28                  ;Right arrow?
  1370.         JNE     RD_NR
  1371.         CMP     DL, 78
  1372.         JE      RD_STEP
  1373.         INC     DL
  1374.         LOCATE
  1375.         JMP     RD_SAVE
  1376.  
  1377. RD_NR:  CMP     AL, 30                  ;Up arrow?
  1378.         JNE     RD_NU
  1379.         CMP     DH, 1
  1380.         JE      RD_STEP
  1381.         DEC     DH
  1382.         LOCATE
  1383.         JMP     RD_SAVE
  1384.  
  1385. RD_STEP:    LOCATE                      ;Intermediate step for long range
  1386.         JMP RD_DONE                     ;conditional jump
  1387.  
  1388. RD_NU:  CMP     AL, 31                  ;Down arrow?
  1389.         JNE     RD_ND
  1390. RD_DOWN:        CMP     DH, 22
  1391.         JE      RD_BOTTOM
  1392.         INC     DH
  1393.         LOCATE
  1394.         JMP     RD_SAVE
  1395. RD_BOTTOM:  SCROLL_UP 1, 1, 41, 22, 78  ;Scroll 1 line if neccessary
  1396.         LOCATE
  1397.         JMP     RD_DONE
  1398.  
  1399. RD_ND:  CMP     AL, CR                  ;Carriage return?
  1400.         JNE     RD_NC
  1401.         MOV     DL, 41
  1402.         JMP     RD_DOWN
  1403.  
  1404. RD_NC:  CMP     AL, LF                  ;Line feed? (Interpret like down arrow)
  1405.         JE      RD_DOWN
  1406.         CMP     AL, 0BH                 ;Vertical tab? (same as down arrow)
  1407.         JE      RD_DOWN
  1408.         CMP     AL, 0CH                 ;Form feed? (same as down arrow)
  1409.         JE      RD_DOWN
  1410.  
  1411. ;Display non-movement characters
  1412.         CMP     DL, 79                  ;Wrap line if neede
  1413.         JNE     RD_SHOW
  1414.         MOV     DL, 41
  1415.         CMP     DH, 22
  1416.         JNE     RD_LINE
  1417.         SCROLL_UP     1, 1, 41, 22, 78  ;Scroll 1 line if needed
  1418.         JMP     RD_SHOW
  1419.  
  1420. RD_LINE:   INC     DH                   ;Move down one line for wrap
  1421. RD_SHOW:   LOCATE                       ;Position cursor
  1422.         MOV     AH, 2
  1423.         MOV     DL, AL
  1424.         INT     21H                     ;Display character
  1425.  
  1426.         MOV     AH, 3
  1427.         MOV     BH, 0
  1428.         INT     10H                     ;Determine current location of cursor
  1429. RD_SAVE:
  1430.         MOV     RX_POSITION, DX         ;Store location
  1431.  
  1432. RD_DONE:
  1433.         POP     DI
  1434.         POP     DX
  1435.         POP     CX
  1436.         POP     BX
  1437.         POP     AX
  1438.         RET
  1439.  
  1440. RX_DISPLAY   ENDP
  1441.  
  1442. ;===============================================================================
  1443. ;
  1444. ;       ENQUEUE Subroutine:
  1445. ;
  1446. ;       Used to enqueue the character in AL into specified queue.
  1447. ;
  1448. ;       Input:  AL = character to be enqueued
  1449. ;               DI = pointer to queue
  1450. ;
  1451. ;       Output: CF = 1 if attempted enqueue failed due to full queue
  1452. ;               CF = 0 otherwise
  1453. ;               [DI].REAR updated
  1454. ;               [DI].COUNT incremented if enqueue successful
  1455. ;               [DI].NMSGS incremented if character is EOM
  1456. ;               THRE interupts enabled if character is EOM
  1457. ;
  1458. ;===============================================================================
  1459.  
  1460. ENQUEUE PROC    NEAR
  1461.  
  1462.         PUSH    DX
  1463.         PUSH    SI
  1464.  
  1465.         CMP     DI, OFFSET RQ           ;Don't check RQ for full queue
  1466.         JE      ENQ1
  1467.  
  1468.         CMP     AL, EOM                 ;Don't check for full queue if EOM
  1469.         JNE     TQ_NOT_EOM
  1470.         MOV     LMSG, 0
  1471.         JMP     ENQ1
  1472.  
  1473. TQ_NOT_EOM:
  1474.         CMP     LMSG, MSGCAP            ;Check TQ for full queue
  1475.         STC                             ;Assume full queue
  1476.         JNE     ENQ0
  1477.         JMP     DONE_ENQ
  1478.  
  1479. ENQ0:   INC     LMSG                    ;Increment current msg length for TQ
  1480.  
  1481. ENQ1:   MOV     SI, [DI].REAR           ;Adjust the rear pointer
  1482.         CMP     SI, [DI].QBEG
  1483.         JA      ENQ2
  1484.         ADD     SI, QCAPAC
  1485. ENQ2:   DEC     SI
  1486.         MOV     [DI].REAR, SI
  1487.         MOV     [SI], AL                ;Enque the character
  1488.  
  1489.         INC     [DI].COUNT              ;Update queue count
  1490.  
  1491.         CMP     AL, EOM
  1492.         CLC
  1493.         JNE     DONE_ENQ
  1494.         INC     [DI].NMSGS              ;If EOM, increment pending messages
  1495.  
  1496. DONE_ENQ:
  1497.         POP     SI
  1498.         POP     DX
  1499.         RET
  1500.  
  1501. ENQUEUE ENDP
  1502.  
  1503. ;===============================================================================
  1504. ;
  1505. ;       DEQUEUE Subroutine:
  1506. ;
  1507. ;       Used to dequeue a character into AL from specified queue.
  1508. ;
  1509. ;       Input:  DI = pointer to queue
  1510. ;
  1511. ;       Output: AL = character dequeued
  1512. ;               [DI].FRONT updated
  1513. ;               [DI].COUNT decremented
  1514. ;               [DI].NMSGS decremented if character = EOM
  1515. ;
  1516. ;===============================================================================
  1517.  
  1518. DEQUEUE PROC    NEAR
  1519.  
  1520.         PUSH    DX
  1521.         PUSH    SI
  1522.  
  1523.         DEC     [DI].COUNT              ;Update queue counter
  1524.  
  1525.         MOV     SI, [DI].FRONT          ;Adjust the front pointer
  1526.         CMP     SI, [DI].QBEG
  1527.         JA      DEQ1
  1528.         ADD     SI, QCAPAC
  1529. DEQ1:   DEC     SI
  1530.         MOV     [DI].FRONT, SI
  1531.         MOV     AL, [SI]                ;Dequeue the character
  1532.  
  1533.         CMP     AL, EOM                 ;Check for end of message
  1534.         JNE     DEQ2
  1535.         DEC     [DI].NMSGS
  1536.  
  1537. DEQ2:   POP     SI
  1538.         POP     DX
  1539.         RET
  1540.  
  1541. DEQUEUE ENDP
  1542.  
  1543. ;===============================================================================
  1544. ;
  1545. ;       CLEAR_QUEUES   Subroutine:
  1546. ;
  1547. ;       Wipes transmit and receive queues clear for switching modes.
  1548. ;
  1549. ;===============================================================================
  1550.  
  1551. CLEAR_QUEUES    PROC   NEAR
  1552.  
  1553.         PUSH    AX
  1554.  
  1555.         MOV     AX, RQ.QBEG             ;Reinitialize receive queue
  1556.         ADD     AX, QCAPAC
  1557.         MOV     RQ.FRONT, AX
  1558.         MOV     RQ.REAR, AX
  1559.         MOV     RQ.COUNT, 0
  1560.         MOV     RQ.NMSGS, 0
  1561.  
  1562.         MOV     AX, TQ.QBEG             ;Reinitialize transmit queue
  1563.         ADD     AX, QCAPAC
  1564.         MOV     TQ.FRONT, AX
  1565.         MOV     TQ.REAR, AX
  1566.         MOV     TQ.COUNT, 0
  1567.         MOV     TQ.NMSGS, 0
  1568.  
  1569.         POP     AX
  1570.         RET
  1571.  
  1572. CLEAR_QUEUES    ENDP
  1573.  
  1574. ;===============================================================================
  1575. ;
  1576. ;       Queue Structures:
  1577. ;
  1578. ;       TQ is used to hold up to 512 characters before transmission.
  1579. ;       RQ is used to hold up to 512 characters, after reception, but
  1580. ;       before display.
  1581. ;
  1582. ;===============================================================================
  1583.  
  1584. QSTRUC  STRUC
  1585.         FRONT   DW      ?               ;Ptr to last character dequeued
  1586.         REAR    DW      ?               ;Ptr to last character enqueued
  1587.         QBEG    DW      ?               ;Offset of first byte of queue
  1588.         COUNT   DW      ?               ;Number of bytes currently in queue
  1589.         NMSGS   DW      ?               ;Number of messages pending
  1590. QSTRUC  ENDS
  1591.  
  1592. QCAPAC  EQU     512
  1593.  
  1594. TQBEG   DB      QCAPAC DUP('T')         ;Allocate space for queues
  1595. RQBEG   DB      QCAPAC DUP('R')
  1596.  
  1597. ;Initialize queues
  1598. TQ      QSTRUC  <TQBEG+QCAPAC, TQBEG+QCAPAC, TQBEG, 0, 0>
  1599. RQ      QSTRUC  <RQBEG+QCAPAC, RQBEG+QCAPAC, RQBEG, 0, 0>
  1600.  
  1601.  
  1602. CSEG    ENDS
  1603.         END     MAIN
  1604.